#include "MarsPrecompile.h"

#include "MarsSceneNode.h"
#include "MarsSpatial.h"
#include "MarsTransformationData.h"

using namespace Core;
using namespace SceneGraph;
using namespace GObject;

const std::string DEFAULT_SCENE_NODE_NAME = "DefaultSceneNode";

uint32 SceneNode::m_uiSceneNodeCount = 0;

SceneNode::SceneNode( SceneNode* pParentNode )
	: m_pParentNode( pParentNode )
{
	std::stringstream strStream;
	strStream << DEFAULT_SCENE_NODE_NAME << m_uiSceneNodeCount++;
	m_strName = strStream.str();

	Initialize();
}

SceneNode::SceneNode( const std::string& strName, SceneNode* pParentNode )
	: m_strName( strName )
	, m_pParentNode( pParentNode )
{
	Initialize();
}

SceneNode::~SceneNode()
{

}

void SceneNode::Initialize()
{
	m_pSpatial = new Spatial();
	m_pTransform = new TransformationData();
}

void SceneNode::Shutdown()
{
	SAFE_DELETE( m_pSpatial );
	SAFE_DELETE( m_pTransform );
}

void SceneNode::AddChild( SceneNode* pSceneNode )
{
	SceneNodeMapItr it = m_mapChildNodes.find( pSceneNode->m_strName );
	if ( it != m_mapChildNodes.end() )
		return;

	m_mapChildNodes[ pSceneNode->m_strName ] = pSceneNode;
}

void SceneNode::RemoveChild( SceneNode* pChildSceneNode )
{
	RemoveChild( pChildSceneNode->m_strName );
}

void SceneNode::RemoveChild( const std::string& strName )
{
	SceneNodeMapItr it = m_mapChildNodes.find( strName );
	if ( it == m_mapChildNodes.end() )
		return;

	m_mapChildNodes.erase( it );
}

void SceneNode::SetParent( SceneNode* pParentNode )
{
	if ( m_pParentNode == pParentNode )
		return;

	if ( m_pParentNode )
		m_pParentNode->RemoveChild( this );

	if ( pParentNode )
		pParentNode->AddChild( this );

	m_pParentNode = pParentNode;
}

void SceneNode::Update( const XMMATRIX& matParentWorld )
{
	if ( m_pSpatial->IsNeedUpdate() )
		UpdateTransformation( matParentWorld );

	SceneNodeMapItr it = m_mapChildNodes.begin();
	SceneNodeMapItr end = m_mapChildNodes.end();
	for ( ; it != end; ++it )
	{
		it->second->Update( m_pTransform->m_worldTransformation );
	}

	UpdateBounding();
}

void SceneNode::UpdateTransformation( const XMMATRIX& matParentWorld )
{
	XMMATRIX rotationMat = XMMatrixRotationRollPitchYawFromVector( m_pSpatial->m_rotate );
	XMMATRIX translationMat = XMMatrixTranslationFromVector( m_pSpatial->m_position );
	XMMATRIX scalingMat = XMMatrixScalingFromVector( m_pSpatial->m_scale );

	m_pTransform->m_localTransformation = scalingMat * rotationMat * translationMat;
	m_pSpatial->SetNeedUpdate( false );

	m_pTransform->m_worldTransformation = m_pTransform->m_localTransformation * matParentWorld;
}

void SceneNode::UpdateBounding()
{

}

void SceneNode::Render( const Camera& camera, RenderObjectArray& arrRenderObjects )
{

}